﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using ProgNetComponentsDx.Components;
using System.IO;
using System.Reflection;

namespace BuildHelper.Actions
{
    public abstract class ActionBase
    {
        static int id;
        public string AlertId
        {
            get;
            private set;
        }

        public abstract bool ValidateAll();
        protected abstract void _Start();
        protected abstract void _Cancel();
        protected virtual void PreStart()
        {
            AlertId = "_ACTION_" + id;
            id++;
        }
        protected virtual void ProcessException(Exception ex, string message)
        {
            ex.LogError(message);
            Status = Actions.ActionStatus.Exception;
        }
        public ActionStatus Status
        {
            get;
            protected set;
        }
        
        public virtual bool Start()
        {
            if (Status == Actions.ActionStatus.InProgress)
            {
                FormMain.Instance.ShowDxInfoDialog("Operacja w toku.");
                return false;
            }
            if (!ValidateAll())
            {
                return false;
            }
            Status = Actions.ActionStatus.InProgress;
            bool result = false;
            try
            {
                PreStart();
                _Start();
                result = true;
            }
            catch (Exception ex)
            {
                ProcessException(ex, "Start");
            }
            return result;
        }

        public virtual bool Cancel()
        {
            bool result = false;
            try
            {
                _Cancel();
                Status = Actions.ActionStatus.Canceled;
                result = true;
            }
            catch (Exception ex)
            {
                ProcessException(ex, "Cancel");
            }
            return result;
        }
    }

    public abstract class ProcessActionBase : ActionBase
    {
        protected ProcessActionBase()
        {
            FileAppender = new FileBgAppender();
        }

        public event DataReceivedEventHandler DataReceived;
        public bool LogToFile
        {
            get;
            set;
        }
        
        protected Process TheProcess
        {
            get;
            private set;
        }
        
        public string LogFile
        {
            get { return FileAppender.FileName; }
        }
        
        private FileBgAppender FileAppender
        {
            get;
            set;
        }
        
        protected override void PreStart()
        {
            base.PreStart();
            if (LogToFile)
            {
                FileAppender.FileName = Path.GetRandomFileName();
                FileAppender.Start();
            }
            TheProcess = GlobalTools.CreateCMDProcess(Process_Data);
        }

        protected override void _Cancel()
        {
            FinishProcess();
        }

        protected abstract void _OnDataReceived(string str);

        protected virtual bool ShouldAppendToFile(string str)
        {
            return true;
        }

        protected void Process_Data(object sender, DataReceivedEventArgs e)
        {
            if (Status == ActionStatus.InProgress)
            {
                string str = e.Data.AsString();
                if (FileAppender != null && ShouldAppendToFile(str))
                {
                    FileAppender.Append(str);
                }

                _OnDataReceived(str);
                
                if (DataReceived != null)
                    DataReceived(sender, e);

            }
        }

        protected virtual void FinishProcess()
        {
            try
            {
                FileAppender.Finish();
            }
            catch (Exception ex)
            {
                ex.LogError("FileAppender.Finish()");
            }
            if (TheProcess != null)
            {
                try
                {
                    TheProcess.KillProcessTree();
                }
                finally
                {
                    try
                    {
                        TheProcess.Dispose();
                    }
                    finally
                    {
                        TheProcess = null;
                    }
                }
            }
        }
        
        protected override void ProcessException(Exception ex, string message)
        {
            base.ProcessException(ex, message);
            FinishProcess();
        }
    }

    public delegate void ProgressHandler(string str);

    public enum ActionStatus
    {
        None,
        InProgress,
        Finished,
        Error,
        Exception,
        Canceled
    }
}
